package com.ljj.examisto.data.service

import android.annotation.SuppressLint
import android.app.AlarmManager
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.CountDownTimer
import android.os.IBinder
import android.provider.Settings
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.work.WorkManager
import com.ljj.examisto.R
import com.ljj.examisto.receiver.ReminderBroadcastReceiver
import com.ljj.examisto.ui.activity.HomeActivity
import com.ljj.examisto.util.DatabaseHelper
import com.ljj.examisto.util.ExamContract
import com.ljj.examisto.util.Logger.TAG
import com.ljj.examisto.util.NotificationChannelInfo
import com.ljj.examisto.util.ReminderContract
import com.ljj.examisto.widget.ExamCountdownWidget
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit

class TimeService : Service() {
    companion object {
        private const val NOTIFICATION_ID = 314159
        private const val ACTION_EXAM_CHANGE = "com.ljj.examisto.ACTION_EXAM_CHANGE"
        private const val ACTION_REMINDER_CHANGE = "com.ljj.examisto.ACTION_REMINDER_CHANGE"
        private const val TIME_FORMAT = "yyyyMMddHHmm"
        fun startService(context: Context) {
            val intent = Intent(context, TimeService::class.java)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(intent)
            } else {
                context.startService(intent)
            }
        }
        fun stopService(context: Context) {
            val intent = Intent(context, TimeService::class.java)
            context.stopService(intent)
        }
    }
    private lateinit var dbHelper: DatabaseHelper
    private lateinit var scheduler: ScheduledExecutorService
    private lateinit var countdownTimer: CountDownTimer
    private lateinit var notificationManager: NotificationManager
    private lateinit var alarmManager: AlarmManager
    private lateinit var examChangeReceiver: BroadcastReceiver
    private lateinit var reminderChangeReceiver: BroadcastReceiver
    private var checkTime: Long = 0

    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "TimeService服务开始")
        initProperties()
        registerReceivers()
        startForegroundNotification()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        checkAndUpdateDatabase()
        return START_STICKY
    }

    override fun onDestroy() {
        cleanupResources()
        resetWidgets()
        super.onDestroy()
    }

    override fun onBind(intent: Intent?): IBinder? = null

    /* 流程函数 */
    private fun initProperties() {
        dbHelper = DatabaseHelper.getInstance(this)
        scheduler = Executors.newSingleThreadScheduledExecutor()
        notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
        checkTime = getCurrentTime()
    }

    @SuppressLint("UnspecifiedRegisterReceiverFlag", "InlinedApi")
    private fun registerReceivers() {
        /** 考试变化监听器 */
        examChangeReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                if (intent?.action == ACTION_EXAM_CHANGE) {
                    Log.d(TAG, "接收到考试变化广播")
                    checkAndUpdateDatabase()
                }
            }
        }
        LocalBroadcastManager.getInstance(this).registerReceiver(examChangeReceiver, IntentFilter(ACTION_EXAM_CHANGE))
        /** 提醒变化监听器 */
        reminderChangeReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                if (intent.action == ACTION_REMINDER_CHANGE) {
                    Log.d(TAG, "接收到提醒变化广播")
                    updateAllReminders(context)
                }
            }
        }
        LocalBroadcastManager.getInstance(this).registerReceiver(reminderChangeReceiver, IntentFilter(ACTION_REMINDER_CHANGE))
    }

    private fun startForegroundNotification() {
        val notification = buildNotification(
            getString(R.string.service_started_title),
            getString(R.string.service_started_message)
        )
        startForeground(NOTIFICATION_ID, notification)
    }

    private fun cleanupResources() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(examChangeReceiver)
        LocalBroadcastManager.getInstance(this).unregisterReceiver(reminderChangeReceiver)
        cancelCountdownTimer()
        shutdownScheduler()
    }

    private fun resetWidgets() {
        val intent = Intent(this, ExamCountdownWidget::class.java)
        intent.action = ExamCountdownWidget.ACTION_APPWIDGET_RESET
        sendBroadcast(intent)
    }

    /* 工具函数 */
    // CountdownTimer相关函数
    private fun createCountdownTimer(examName: String, millisInFuture: Long): CountDownTimer {
        return object : CountDownTimer(millisInFuture, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                val timeLeft = formatTime(millisUntilFinished)
                updateDisplays(examName, timeLeft)
            }
            override fun onFinish() {
                updateDisplays(examName, getString(R.string.exam_started_message))
            }
        }
    }

    private fun setupCountdownTimer(examName: String, startTime: Long) {
        cancelCountdownTimer()
        val startCalendar = parseTimeFormat(startTime)
        val startMillis = startCalendar.timeInMillis
        val currentMillis = System.currentTimeMillis()
        val countdownMillis = startMillis - currentMillis
        if (countdownMillis > 0) {
            countdownTimer = createCountdownTimer(examName, countdownMillis)
            countdownTimer.start()
            Log.d(TAG, "setupCountdownTimer: 考试 $examName 未到期，创建了倒计时")
        } else {
            updateDisplays(examName, getString(R.string.exam_started_message))
            Log.d(TAG, "setupCountdownTimer: 考试 $examName 到期，考试已开始")
        }
    }

    private fun cancelCountdownTimer() {
        if (::countdownTimer.isInitialized) {
            countdownTimer.cancel()
        }
    }

    // Scheduler相关函数
    private fun scheduleNextCheck() {
        val delayMinutes = calculateDelayMinutes(checkTime)
        Log.d(TAG, "安排下一次检查在${delayMinutes}分钟之后")
        scheduler.shutdownNow()
        scheduler = Executors.newSingleThreadScheduledExecutor()
        scheduler.schedule(
            { checkAndUpdateDatabase() },
            delayMinutes,
            TimeUnit.MINUTES
        )
    }

    private fun shutdownScheduler() {
        try {
            scheduler.shutdownNow()
        } catch (e: Exception) {
            Log.e(TAG, "关闭Scheduler时出错：", e)
        }
    }

    // Reminder相关函数
    private fun setupRemindersForExam(examName: String) {
        try {
            val remindersCursor = dbHelper.getRemindersByName(examName) ?: return
            if (remindersCursor.moveToFirst()) {
                do {
                    val seconds = remindersCursor.getInt(
                        remindersCursor.getColumnIndexOrThrow(ReminderContract.COLUMN_SECONDS)
                    )
                    val reminderTime = remindersCursor.getLong(
                        remindersCursor.getColumnIndexOrThrow(ReminderContract.COLUMN_REMINDER_TIME)
                    )
                    val type = remindersCursor.getString(
                        remindersCursor.getColumnIndexOrThrow(ReminderContract.COLUMN_TYPE)
                    )
                    // 使用统一的 requestCode
                    val requestCode = getReminderRequestCode(examName, reminderTime)
                    scheduleReminder(this, examName, seconds, reminderTime, type, requestCode)
                } while (remindersCursor.moveToNext())
            }
            remindersCursor.close()
        } catch (e: Exception) {
            Log.e(TAG, "获取 $examName 的提醒失败", e)
        }
    }

    private fun scheduleReminder(context: Context, examName: String, seconds: Int, reminderTime: Long, type: String, requestCode: Int) {
        try {
            // 1. 解析 reminderTime 为 Calendar 对象
            val calendar = parseTimeFormat(reminderTime)
            // 2. 判断 reminderTime 是否已过当前时间
            val currentTimeMillis = System.currentTimeMillis()
            if (calendar.timeInMillis < currentTimeMillis) {
                Log.d(TAG, "提醒时间已过，不会设置闹钟：$examName 在 ${calendar.time}")
                return
            }
            // 3. 创建 Intent，用于发送广播给 ReminderBroadcastReceiver
            val intent = Intent(context, ReminderBroadcastReceiver::class.java).apply {
                action = "com.ljj.examisto.ACTION_REMIND"
                putExtra("examName", examName)
                putExtra("seconds", seconds)
                putExtra("type", type)
                putExtra("requestCode", requestCode)
            }
            val pendingIntent = PendingIntent.getBroadcast(
                context,
                requestCode,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )
            // 4. 获取 AlarmManager 实例
            val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager
            // 5. 设置精确闹钟
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
                // Android 12+ 且无权限时，引导用户去设置
                context.startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
            } else {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    calendar.timeInMillis,
                    pendingIntent
                )
            }
            Log.d(TAG, "提醒已设置：$examName 在 ${calendar.time}")
        } catch (e: Exception) {
            Log.e(TAG, "设置提醒失败", e)
        }
    }

    private fun updateAllReminders(context: Context) {
        // 取消所有已设置的提醒
        cancelAllReminders(context)
        // 重新设置所有现存的提醒
        val examNames = dbHelper.getExamNames()
        if (examNames.isNotEmpty()) {
            for (examName in examNames) {
                setupRemindersForExam(examName)
            }
        }
    }

    private fun cancelAllReminders(context: Context) {
        try {
            val examNames = dbHelper.getExamNames()
            if (examNames.isEmpty()) {
                Log.d(TAG, "没有考试记录，无需取消提醒")
                return
            }
            for (examName in examNames) {
                val cursor = dbHelper.getRemindersByName(examName) ?: continue
                cursor.use { remindersCursor ->
                    if (!remindersCursor.moveToFirst()) {
                        Log.d(TAG, "考试 '$examName' 没有提醒记录")
                        return@use
                    }
                    do {
                        val reminderTime = remindersCursor.getLong(
                            remindersCursor.getColumnIndexOrThrow(ReminderContract.COLUMN_REMINDER_TIME)
                        )
                        val requestCode = getReminderRequestCode(examName, reminderTime)
                        cancelReminder(context, requestCode)
                    } while (remindersCursor.moveToNext())
                }
            }
            Log.d(TAG, "所有提醒已成功取消")
        } catch (e: Exception) {
            Log.e(TAG, "取消所有提醒时出错", e)
        }
    }

    private fun cancelReminder(context: Context, requestCode: Int) {
        try {
            WorkManager.getInstance(context).cancelAllWorkByTag("reminder_$requestCode")
            Log.d(TAG, "提醒已取消，requestCode: $requestCode")
        } catch (e: Exception) {
            Log.e(TAG, "取消提醒时出错，requestCode: $requestCode，error：", e)
        }
    }

    // Notification相关函数
    private fun buildNotification(title: String, content: String): Notification {
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            Intent(this, HomeActivity::class.java),
            PendingIntent.FLAG_IMMUTABLE
        )
        return NotificationCompat.Builder(this, NotificationChannelInfo.SERVICE_CHANNEL_ID)
            .setContentTitle(title)
            .setContentText(content)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentIntent(pendingIntent) // 跳转主页
            .setOngoing(true)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()
    }

    private fun updateNotification(title: String, content: String) {
        val notification = buildNotification(title, content)
        notificationManager.notify(NOTIFICATION_ID, notification)
    }


    // Widget相关函数
    private fun updateWidgets(examName: String, timeLeft: String) {
        val intent = Intent(this, ExamCountdownWidget::class.java)
        intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
        intent.putExtra("examName", examName)
        intent.putExtra("timeLeft", timeLeft)
        sendBroadcast(intent)
    }

    // 显示更新函数
    /**
     * 同时更新 通知 和 组件
     */
    private fun updateDisplays(title: String, content: String) {
        updateNotification(title, content)
        updateWidgets(title, content)
    }

    // 数据库相关函数
    fun checkAndUpdateDatabase() {
        Log.d(TAG, "checkAndUpdateDatabase: 到期检查数据库")
        try {
            dbHelper.deleteExpiredExams()
            val nextExam = dbHelper.getLatestExam()
            if (nextExam != null) {
                handleActiveExamForCountdown(nextExam)
            } else {
                handleNoExamForCountdown()
            }
            nextExam?.close()
        } catch (e: Exception) {
            Log.e(TAG, "Error in checkAndUpdateDatabase", e)
            updateDisplays(
                getString(R.string.error_title),
                getString(R.string.error_reading_exams)
            )
        }
    }

    private fun handleActiveExamForCountdown(exam: android.database.Cursor) {
        val examName = exam.getString(exam.getColumnIndexOrThrow(ExamContract.COLUMN_EXAM_NAME))
        val endTime = exam.getLong(exam.getColumnIndexOrThrow(ExamContract.COLUMN_END_TIME))
        val startTime = exam.getLong(exam.getColumnIndexOrThrow(ExamContract.COLUMN_START_TIME))
        checkTime = endTime
        scheduleNextCheck()
        setupCountdownTimer(examName, startTime)
    }

    private fun handleNoExamForCountdown() {
        cancelCountdownTimer()
        updateDisplays(
            getString(R.string.no_exams_title),
            getString(R.string.no_exams_message)
        )
    }

    // 通用工具函数
    private fun getCurrentTime(): Long {
        return SimpleDateFormat(TIME_FORMAT, Locale.getDefault())
            .format(Date())
            .toLong()
    }

    private fun calculateDelayMinutes(targetTime: Long): Long {
        val currentTime = getCurrentTime()
        return (targetTime - currentTime).coerceAtLeast(0)
    }

    private fun parseTimeFormat(time: Long): Calendar {
        val timeStr = time.toString()
        require(timeStr.length == 12) { "Time format must be 12 digits (yyyyMMddHHmm)" }
        return Calendar.getInstance().apply {
            set(Calendar.YEAR, timeStr.substring(0, 4).toInt())
            set(Calendar.MONTH, timeStr.substring(4, 6).toInt() - 1)
            set(Calendar.DAY_OF_MONTH, timeStr.substring(6, 8).toInt())
            set(Calendar.HOUR_OF_DAY, timeStr.substring(8, 10).toInt())
            set(Calendar.MINUTE, timeStr.substring(10, 12).toInt())
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }
    }

    private fun formatTime(millis: Long): String {
        val seconds = millis / 1000
        val hours = seconds / 3600
        val minutes = (seconds % 3600) / 60
        val secs = seconds % 60
        return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, secs)
    }

    private fun getReminderRequestCode(examName: String, reminderTime: Long): Int {
        return "$examName-$reminderTime".hashCode()
    }
}